/**
 * 
 */
package com.google.code.maven.plugin.http.client;

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;

import com.google.code.maven.plugin.http.client.config.ConfigurationContext;
import com.google.code.maven.plugin.http.client.config.ProxyConfiguration;
import com.google.code.maven.plugin.http.client.config.RequestConfiguration;
import com.google.code.maven.plugin.http.client.config.TransformerConfiguration;
import com.google.code.maven.plugin.http.client.transformer.HttpEntityToContentReader;
import com.google.code.maven.plugin.http.client.transformer.BufferedReaderConsolePrinter;
import com.google.code.maven.plugin.http.client.transformer.Transformer;

/**
 * Process an http request and transforms the response from the specified flow of transformers.
 * 
 * @author Nadim Benabdenbi
 * @version 1.0
 * @since JDK1.6
 * 
 * @goal execute
 * @requiresProject
 */
public class HttpClientMojo extends AbstractMojo {
	
	/**
	 * The Maven project
	 * 
	 * @parameter expression="${project}"
	 * @required
	 */
	private MavenProject project;
	
	/**
	 * fail safe indicator e.g. indicates if a mojo failure should break the build process.
	 * 
	 * @parameter default-value="true"
	 */
	private boolean failSafe = true;
	
	/**
	 * the request configuration
	 * 
	 * @parameter
	 * @required
	 */
	private RequestConfiguration request;
	
	/**
	 * the proxy configuration if any
	 * 
	 * @parameter
	 */
	private ProxyConfiguration proxy;
	
	/**
	 * default flow of transformers consists on printing the response content to the console
	 * 
	 * @parameter
	 */
	private TransformerConfiguration transformers[];
	
	/**
	 * the bean resolver
	 */
	private transient ConfigurationContext configurationContext;
	
	/**
	 * 
	 */
	public HttpClientMojo() {
		super();
		transformers = new TransformerConfiguration[2];
		TransformerConfiguration transformer = new TransformerConfiguration();
		transformer.setClassName(HttpEntityToContentReader.class.getName());
		transformers[0] = transformer;
		transformer = new TransformerConfiguration();
		transformer.setClassName(BufferedReaderConsolePrinter.class.getName());
		transformers[1] = transformer;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.maven.plugin.Mojo#execute()
	 */
	@SuppressWarnings("unchecked")
	public void execute() throws MojoExecutionException, MojoFailureException {
		configurationContext = new ConfigurationContext(project);
		configurationContext.registerConfigFactory(proxy);
		configurationContext.registerConfigFactory(request);
		Request request = this.request.build(configurationContext.getBeanFactory());
		Proxy proxy = this.proxy == null ? null : this.proxy.build(configurationContext.getBeanFactory());
		DefaultHttpClient httpclient = new DefaultHttpClient();
		try {
			// client
			HttpEntity entity = HttpRequestUtils.query(httpclient, request, proxy, getLog());
			long transformTime = System.currentTimeMillis();
			Object current = entity;
			for (TransformerConfiguration configuration : transformers) {
				Transformer transformer = configuration.build(configurationContext.getBeanFactory());
				current = transformer.transform(current, getLog());
			}
			getLog().info("Response processed in " + (System.currentTimeMillis() - transformTime) + "ms");
			httpclient.getConnectionManager().shutdown();
		} catch (ClassCastException cce) {
			if (failSafe) {
				getLog().warn("invalid transformation flow", cce);
			} else {
				throw new MojoExecutionException("invalid transformation flow", cce);
			}
		} catch (ClientProtocolException cpe) {
			if (failSafe) {
				getLog().warn("invalid protocol", cpe);
			} else {
				throw new MojoExecutionException("invalid protocol", cpe);
			}
		} catch (IOException ioe) {
			if (failSafe) {
				getLog().warn("network failure", ioe);
			} else {
				throw new MojoExecutionException("network failure", ioe);
			}
		} catch (MojoExecutionException mee) {
			if (failSafe) {
				getLog().warn("mojo failure", mee);
			} else {
				throw new MojoExecutionException("mojo failure", mee);
			}
		}
	}
	
	/**
	 * project getter.
	 * 
	 * @return the project
	 */
	public MavenProject getProject() {
		return project;
	}
	
	/**
	 * project setter.
	 * 
	 * @param project
	 *            the project to set
	 */
	public void setProject(MavenProject project) {
		this.project = project;
	}
	
	/**
	 * @return the transformers
	 */
	public TransformerConfiguration[] getTransformers() {
		return transformers;
	}
	
	/**
	 * @param transformers
	 *            the transformers to set
	 */
	public void setTransformers(TransformerConfiguration transformers[]) {
		this.transformers = transformers;
	}
	
	/**
	 * failSafe getter.
	 * 
	 * @return the failSafe
	 */
	public boolean isFailSafe() {
		return failSafe;
	}
	
	/**
	 * failSafe setter.
	 * 
	 * @param failSafe
	 *            the failSafe to set
	 */
	public void setFailSafe(boolean failSafe) {
		this.failSafe = failSafe;
	}
	
	/**
	 * request getter.
	 * 
	 * @return the request
	 */
	public RequestConfiguration getRequest() {
		return request;
	}
	
	/**
	 * request setter.
	 * 
	 * @param request
	 *            the request to set
	 */
	public void setRequest(RequestConfiguration request) {
		this.request = request;
	}
	
	/**
	 * proxy getter.
	 * 
	 * @return the proxy
	 */
	public ProxyConfiguration getProxy() {
		return proxy;
	}
	
	/**
	 * proxy setter.
	 * 
	 * @param proxy
	 *            the proxy to set
	 */
	public void setProxy(ProxyConfiguration proxy) {
		this.proxy = proxy;
	}
	
	/**
	 * @return the parser
	 */
	public ConfigurationContext getParser() {
		return configurationContext;
	}
	
}
